package cn.lenchu.util;

import lombok.NonNull;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.lang.Nullable;
import org.springframework.web.client.RestTemplate;

import java.net.URI;

/**
 * @author lenchu
 */
public class HttpUtil {
    private static RestTemplate defaultRestTemplate;
    private static RestTemplate newDefaultRestTemplate() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(5000);
        factory.setReadTimeout(5000);
        return new RestTemplate(factory);
    }

    private final RestTemplate restTemplate;

    private HttpHeaders defaultHeader;

    private final String baseUrl;

    private HttpUtil(RestTemplate restTemplate, String baseUrl, HttpHeaders defaultHeader) {
        this.restTemplate = restTemplate;
        this.defaultHeader = defaultHeader;
        this.baseUrl = baseUrl;
    }

    private HttpHeaders resolveHeaders(HttpHeaders headers) {
        if (headers != null) {
            if (this.defaultHeader != null) {
                headers.addAll(this.defaultHeader);
            }
            return headers;
        }
        return this.defaultHeader;
    }

    private URI resolveUri(String url) {
        if (StringUtils.isNotBlank(baseUrl)) {
            return URI.create(baseUrl + url);
        }
        return URI.create(url);
    }

    public ResponseEntity<String> get(String url) {
        return this.execute(url, HttpMethod.GET, null, null, String.class);
    }

    public ResponseEntity<String> get(String url, HttpHeaders headers) {
        return this.execute(url, HttpMethod.GET, null, headers, String.class);
    }

    public <R> ResponseEntity<R> get(String url, HttpHeaders headers, Class<R> responseBodyType) {
        return this.execute(url, HttpMethod.GET, null, headers, responseBodyType);
    }

    public <E> ResponseEntity<String> post(String url, E body) {
        return this.execute(url, HttpMethod.POST, body, null, String.class);
    }

    public <E> ResponseEntity<String> post(String url, E body, HttpHeaders headers) {
        return this.execute(url, HttpMethod.POST, body, headers, String.class);
    }

    public <E, R> ResponseEntity<R> post(String url, E body, HttpHeaders headers, Class<R> responseBodyType) {
        return this.execute(url, HttpMethod.POST, body, headers, responseBodyType);
    }

    public ResponseEntity<String> execute(String url, HttpMethod method, String body, HttpHeaders headers) {
        return this.execute(url, method, body, headers, String.class);
    }

    public <T> ResponseEntity<T> execute(String url, HttpMethod method, Object body, HttpHeaders headers, Class<T> responseBodyType) {
        URI uri = resolveUri(url);
        RequestEntity<Object> requestEntity = new RequestEntity<>(body, resolveHeaders(headers), method, uri);
        return restTemplate.exchange(requestEntity, responseBodyType);
    }

    public void addDefaultHeaders(HttpHeaders headers) {
        if (this.defaultHeader == null) {
            this.defaultHeader = headers;
        }
        if (headers != null) {
            this.defaultHeader.addAll(headers);
        }
    }

    public void addDefaultHeader(String header, String value) {
        if (this.defaultHeader == null) {
            this.defaultHeader = new HttpHeaders();
        }
        this.defaultHeader.add(header, value);
    }

    public void removeDefaultHeader(String header) {
        if (this.defaultHeader != null) {
            this.defaultHeader.remove(header);
        }
    }

    public static HttpUtil newInstance() {
        if (defaultRestTemplate == null) {
            defaultRestTemplate = newDefaultRestTemplate();
        }
        return new HttpUtil(defaultRestTemplate, null, null);
    }

    public static HttpUtil newInstance(@NonNull RestTemplate restTemplate) {
        return new HttpUtil(restTemplate, null, null);
    }

    public static HttpUtil newInstance(@NonNull RestTemplate restTemplate, @Nullable String baseUrl) {
        return new HttpUtil(restTemplate, baseUrl, null);
    }

    public static HttpUtil newInstance(@NonNull RestTemplate restTemplate, @Nullable String baseUrl, @Nullable HttpHeaders defaultHeader) {
        return new HttpUtil(restTemplate, baseUrl, defaultHeader);
    }
}
